cssnode: Track invalid children
authorBenjamin Otte <otte@redhat.com>
Sun, 1 Mar 2015 12:14:01 +0000 (13:14 +0100)
committerBenjamin Otte <otte@redhat.com>
Wed, 18 Mar 2015 14:23:33 +0000 (15:23 +0100)
We need to properly track if a node needs to propagate invalidation
state information to its children. We didn't do this properly before and
that could lead to us forgetting to invalidate nodes in corner cases.

gtk/gtkcssnode.c
gtk/gtkcssnodeprivate.h

index 547cfb91c9a31fcec2a4aea9e6e071edde4b0437..462d55039b79011cd6f5535966fc93b7b5342070 100644 (file)
@@ -499,6 +499,8 @@ gtk_css_node_reposition (GtkCssNode *node,
             gtk_css_node_set_children_changed (parent);
           g_object_ref (node);
 
+          if (node->pending_changes)
+            parent->needs_propagation = TRUE;
           if (node->invalid && node->visible)
             gtk_css_node_set_invalid (parent, TRUE);
         }
@@ -621,7 +623,7 @@ gtk_css_node_propagate_pending_changes (GtkCssNode *cssnode,
   if (style_changed)
     change |= GTK_CSS_CHANGE_PARENT_STYLE;
 
-  if (!cssnode->invalid && change == 0)
+  if (!cssnode->needs_propagation && change == 0)
     return;
 
   for (child = gtk_css_node_get_first_child (cssnode);
@@ -633,19 +635,20 @@ gtk_css_node_propagate_pending_changes (GtkCssNode *cssnode,
       if (child->visible)
         change |= _gtk_css_change_for_sibling (child_change);
     }
+
+  cssnode->needs_propagation = FALSE;
 }
 
 static gboolean
 gtk_css_node_needs_new_style (GtkCssNode *cssnode)
 {
-  return cssnode->style_is_invalid;
+  return cssnode->style_is_invalid || cssnode->needs_propagation;
 }
 
 static void
 gtk_css_node_ensure_style (GtkCssNode *cssnode,
                            gint64      current_time)
 {
-  GtkCssStyle *new_style;
   gboolean style_changed;
 
   if (!gtk_css_node_needs_new_style (cssnode))
@@ -654,16 +657,25 @@ gtk_css_node_ensure_style (GtkCssNode *cssnode,
   if (cssnode->parent)
     gtk_css_node_ensure_style (cssnode->parent, current_time);
 
-  if (cssnode->previous_sibling)
-    gtk_css_node_ensure_style (cssnode->previous_sibling, current_time);
+  if (cssnode->style_is_invalid)
+    {
+      GtkCssStyle *new_style;
 
-  new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->update_style (cssnode,
-                                                              cssnode->pending_changes,
-                                                              current_time,
-                                                              cssnode->style);
+      if (cssnode->previous_sibling)
+        gtk_css_node_ensure_style (cssnode->previous_sibling, current_time);
 
-  style_changed = gtk_css_node_set_style (cssnode, new_style);
-  g_object_unref (new_style);
+      new_style = GTK_CSS_NODE_GET_CLASS (cssnode)->update_style (cssnode,
+                                                                  cssnode->pending_changes,
+                                                                  current_time,
+                                                                  cssnode->style);
+
+      style_changed = gtk_css_node_set_style (cssnode, new_style);
+      g_object_unref (new_style);
+    }
+  else
+    {
+      style_changed = FALSE;
+    }
 
   gtk_css_node_propagate_pending_changes (cssnode, style_changed);
 
@@ -886,6 +898,8 @@ gtk_css_node_invalidate (GtkCssNode   *cssnode,
 
   GTK_CSS_NODE_GET_CLASS (cssnode)->invalidate (cssnode);
 
+  if (cssnode->parent)
+    cssnode->parent->needs_propagation = TRUE;
   gtk_css_node_invalidate_style (cssnode);
 }
 
index 00a106a8c280c3dbdd656be6d64b27651d22570b..611bc71b148a50eb390bf4b97ad03b6ba97a01d5 100644 (file)
@@ -52,6 +52,7 @@ struct _GtkCssNode
   guint                  visible :1;            /* node will be skipped when validating or computing styles */
   guint                  invalid :1;            /* node or a child needs to be validated (even if just for animation) */
   guint                  children_changed :1;   /* the children changed since last validation */
+  guint                  needs_propagation :1;  /* children have state changes that need to be propagated to their siblings */
   /* Two invariants hold for this variable:
    * style_is_invalid == TRUE  =>  next_sibling->style_is_invalid == TRUE
    * style_is_invalid == FALSE =>  first_child->style_is_invalid == TRUE